// Copyright Epic Games, Inc. All Rights Reserved.


#include "Audio/LyraAudioMixEffectsSubsystem.h" // 包含Lyra音频混合效果子系统头文件

#include "AudioMixerBlueprintLibrary.h" // 包含音频混合器蓝图库头文件
#include "AudioModulationStatics.h" // 包含音频调制静态函数头文件
#include "Engine/GameInstance.h" // 包含游戏实例头文件
#include "Engine/World.h" // 包含世界头文件
#include "LoadingScreenManager.h" // 包含加载屏幕管理器头文件
#include "LyraAudioSettings.h" // 包含Lyra音频设置头文件
#include "Settings/LyraSettingsLocal.h" // 包含Lyra本地设置头文件
#include "Sound/SoundEffectSubmix.h" // 包含声音效果子混音头文件
#include "SoundControlBus.h" // 包含声音控制总线头文件
#include "SoundControlBusMix.h" // 包含声音控制总线混合头文件

#include UE_INLINE_GENERATED_CPP_BY_NAME(LyraAudioMixEffectsSubsystem) // 包含内联生成的C++代码

class FSubsystemCollectionBase;

/**
 * 初始化子系统
 * @param Collection 子系统集合基类引用
 */
void ULyraAudioMixEffectsSubsystem::Initialize(FSubsystemCollectionBase& Collection)
{
	Super::Initialize(Collection); // 调用父类初始化
}

/**
 * 反初始化子系统
 */
void ULyraAudioMixEffectsSubsystem::Deinitialize()
{
	// 获取加载屏幕管理器并移除委托
	if (ULoadingScreenManager* LoadingScreenManager = UGameInstance::GetSubsystem<ULoadingScreenManager>(GetWorld()->GetGameInstance()))
	{
		LoadingScreenManager->OnLoadingScreenVisibilityChangedDelegate().RemoveAll(this); // 移除所有加载屏幕可见性改变委托
		ApplyOrRemoveLoadingScreenMix(false); // 应用或移除加载屏幕混合
	}

	Super::Deinitialize(); // 调用父类反初始化
}

/**
 * 判断是否应创建子系统
 * @param Outer 外部对象
 * @return 是否应创建子系统
 */
bool ULyraAudioMixEffectsSubsystem::ShouldCreateSubsystem(UObject* Outer) const
{
	bool bShouldCreateSubsystem = Super::ShouldCreateSubsystem(Outer); // 调用父类判断

	if (Outer) // 如果外部对象存在
	{
		if (UWorld* World = Outer->GetWorld()) // 获取世界
		{
			bShouldCreateSubsystem = DoesSupportWorldType(World->WorldType) && bShouldCreateSubsystem; // 根据世界类型判断是否创建子系统
		}
	}

	return bShouldCreateSubsystem; // 返回是否应创建子系统
}

/**
 * 后初始化函数
 */
void ULyraAudioMixEffectsSubsystem::PostInitialize()
{
	// 获取Lyra音频设置默认对象
	if (const ULyraAudioSettings* LyraAudioSettings = GetDefault<ULyraAudioSettings>())
	{
		// 加载默认控制总线混合
		if (UObject* ObjPath = LyraAudioSettings->DefaultControlBusMix.TryLoad())
		{
			if (USoundControlBusMix* SoundControlBusMix = Cast<USoundControlBusMix>(ObjPath))
			{
				DefaultBaseMix = SoundControlBusMix; // 设置默认基础混合
			}
			else
			{
				ensureMsgf(SoundControlBusMix, TEXT("Default Control Bus Mix reference missing from Lyra Audio Settings.")); // 确保控制总线混合存在
			}
		}

		// 加载加载屏幕控制总线混合
		if (UObject* ObjPath = LyraAudioSettings->LoadingScreenControlBusMix.TryLoad())
		{
			if (USoundControlBusMix* SoundControlBusMix = Cast<USoundControlBusMix>(ObjPath))
			{
				LoadingScreenMix = SoundControlBusMix; // 设置加载屏幕混合
			}
			else
			{
				ensureMsgf(SoundControlBusMix, TEXT("Loading Screen Control Bus Mix reference missing from Lyra Audio Settings.")); // 确保控制总线混合存在
			}
		}

		// 加载用户设置控制总线混合
		if (UObject* ObjPath = LyraAudioSettings->UserSettingsControlBusMix.TryLoad())
		{
			if (USoundControlBusMix* SoundControlBusMix = Cast<USoundControlBusMix>(ObjPath))
			{
				UserMix = SoundControlBusMix; // 设置用户混合
			}
			else
			{
				ensureMsgf(SoundControlBusMix, TEXT("User Control Bus Mix reference missing from Lyra Audio Settings.")); // 确保控制总线混合存在
			}
		}

		// 加载总体音量控制总线
		if (UObject* ObjPath = LyraAudioSettings->OverallVolumeControlBus.TryLoad())
		{
			if (USoundControlBus* SoundControlBus = Cast<USoundControlBus>(ObjPath))
			{
				OverallControlBus = SoundControlBus; // 设置总体控制总线
			}
			else
			{
				ensureMsgf(SoundControlBus, TEXT("Overall Control Bus reference missing from Lyra Audio Settings.")); // 确保控制总线存在
			}
		}

		// 加载音乐音量控制总线
		if (UObject* ObjPath = LyraAudioSettings->MusicVolumeControlBus.TryLoad())
		{
			if (USoundControlBus* SoundControlBus = Cast<USoundControlBus>(ObjPath))
			{
				MusicControlBus = SoundControlBus; // 设置音乐控制总线
			}
			else
			{
				ensureMsgf(SoundControlBus, TEXT("Music Control Bus reference missing from Lyra Audio Settings.")); // 确保控制总线存在
			}
		}

		// 加载音效音量控制总线
		if (UObject* ObjPath = LyraAudioSettings->SoundFXVolumeControlBus.TryLoad())
		{
			if (USoundControlBus* SoundControlBus = Cast<USoundControlBus>(ObjPath))
			{
				SoundFXControlBus = SoundControlBus; // 设置音效控制总线
			}
			else
			{
				ensureMsgf(SoundControlBus, TEXT("SoundFX Control Bus reference missing from Lyra Audio Settings.")); // 确保控制总线存在
			}
		}

		// 加载对话音量控制总线
		if (UObject* ObjPath = LyraAudioSettings->DialogueVolumeControlBus.TryLoad())
		{
			if (USoundControlBus* SoundControlBus = Cast<USoundControlBus>(ObjPath))
			{
				DialogueControlBus = SoundControlBus; // 设置对话控制总线
			}
			else
			{
				ensureMsgf(SoundControlBus, TEXT("Dialogue Control Bus reference missing from Lyra Audio Settings.")); // 确保控制总线存在
			}
		}

		// 加载语音聊天音量控制总线
		if (UObject* ObjPath = LyraAudioSettings->VoiceChatVolumeControlBus.TryLoad())
		{
			if (USoundControlBus* SoundControlBus = Cast<USoundControlBus>(ObjPath))
			{
				VoiceChatControlBus = SoundControlBus; // 设置语音聊天控制总线
			}
			else
			{
				ensureMsgf(SoundControlBus, TEXT("VoiceChat Control Bus reference missing from Lyra Audio Settings.")); // 确保控制总线存在
			}
		}

		// 加载HDR子混音效果链
		for (const FLyraSubmixEffectChainMap& SoftSubmixEffectChain : LyraAudioSettings->HDRAudioSubmixEffectChain)
		{
			FLyraAudioSubmixEffectsChain NewEffectChain; // 创建新效果链

			if (UObject* SubmixObjPath = SoftSubmixEffectChain.Submix.LoadSynchronous()) // 同步加载子混音
			{
				if (USoundSubmix* Submix = Cast<USoundSubmix>(SubmixObjPath))
				{
					NewEffectChain.Submix = Submix; // 设置子混音
					TArray<USoundEffectSubmixPreset*> NewPresetChain; // 创建新预设链

					// 加载子混音效果链中的每个效果
					for (const TSoftObjectPtr<USoundEffectSubmixPreset>& SoftEffect : SoftSubmixEffectChain.SubmixEffectChain)
					{
						if (UObject* EffectObjPath = SoftEffect.LoadSynchronous()) // 同步加载效果
						{
							if (USoundEffectSubmixPreset* SubmixPreset = Cast<USoundEffectSubmixPreset>(EffectObjPath))
							{
								NewPresetChain.Add(SubmixPreset); // 添加子混音预设到链中
							}
						}
					}

					NewEffectChain.SubmixEffectChain.Append(NewPresetChain); // 将新预设链附加到效果链
				}
			}

			HDRSubmixEffectChain.Add(NewEffectChain); // 添加新效果链到HDR子混音效果链
		}

		// 加载LDR子混音效果链
		for (const FLyraSubmixEffectChainMap& SoftSubmixEffectChain : LyraAudioSettings->LDRAudioSubmixEffectChain)
		{
			FLyraAudioSubmixEffectsChain NewEffectChain; // 创建新效果链

			if (UObject* SubmixObjPath = SoftSubmixEffectChain.Submix.LoadSynchronous()) // 同步加载子混音
			{
				if (USoundSubmix* Submix = Cast<USoundSubmix>(SubmixObjPath))
				{
					NewEffectChain.Submix = Submix; // 设置子混音
					TArray<USoundEffectSubmixPreset*> NewPresetChain; // 创建新预设链

					// 加载子混音效果链中的每个效果
					for (const TSoftObjectPtr<USoundEffectSubmixPreset>& SoftEffect : SoftSubmixEffectChain.SubmixEffectChain)
					{
						if (UObject* EffectObjPath = SoftEffect.LoadSynchronous()) // 同步加载效果
						{
							if (USoundEffectSubmixPreset* SubmixPreset = Cast<USoundEffectSubmixPreset>(EffectObjPath))
							{
								NewPresetChain.Add(SubmixPreset); // 添加子混音预设到链中
							}
						}
					}

					NewEffectChain.SubmixEffectChain.Append(NewPresetChain); // 将新预设链附加到效果链
				}
			}

			LDRSubmixEffectChain.Add(NewEffectChain); // 添加新效果链到LDR子混音效果链
		}
	}

	// 向加载屏幕管理器注册
	if (ULoadingScreenManager* LoadingScreenManager = UGameInstance::GetSubsystem<ULoadingScreenManager>(GetWorld()->GetGameInstance()))
	{
		LoadingScreenManager->OnLoadingScreenVisibilityChangedDelegate().AddUObject(this, &ThisClass::OnLoadingScreenStatusChanged); // 添加加载屏幕状态改变委托
		ApplyOrRemoveLoadingScreenMix(LoadingScreenManager->GetLoadingScreenDisplayStatus()); // 应用或移除加载屏幕混合
	}
}

/**
 * 世界开始游戏时调用
 * @param InWorld 世界引用
 */
void ULyraAudioMixEffectsSubsystem::OnWorldBeginPlay(UWorld& InWorld)
{
	if (const UWorld* World = InWorld.GetWorld())
	{
		// 激活默认基础混合
		if (DefaultBaseMix)
		{
			UAudioModulationStatics::ActivateBusMix(World, DefaultBaseMix); // 激活总线混合
		}

		// 检索用户设置
		if (const ULyraSettingsLocal* LyraSettingsLocal = GetDefault<ULyraSettingsLocal>())
		{
			// 激活用户混合
			if (UserMix)
			{
				UAudioModulationStatics::ActivateBusMix(World, UserMix); // 激活用户混合

				// 创建各个总线的混合阶段并更新混合
				if (OverallControlBus && MusicControlBus && SoundFXControlBus && DialogueControlBus && VoiceChatControlBus)
				{
					const FSoundControlBusMixStage OverallControlBusMixStage = UAudioModulationStatics::CreateBusMixStage(World, OverallControlBus, LyraSettingsLocal->GetOverallVolume()); // 创建总体控制总线混合阶段
					const FSoundControlBusMixStage MusicControlBusMixStage = UAudioModulationStatics::CreateBusMixStage(World, MusicControlBus, LyraSettingsLocal->GetMusicVolume()); // 创建音乐控制总线混合阶段
					const FSoundControlBusMixStage SoundFXControlBusMixStage = UAudioModulationStatics::CreateBusMixStage(World, SoundFXControlBus, LyraSettingsLocal->GetSoundFXVolume()); // 创建音效控制总线混合阶段
					const FSoundControlBusMixStage DialogueControlBusMixStage = UAudioModulationStatics::CreateBusMixStage(World, DialogueControlBus, LyraSettingsLocal->GetDialogueVolume()); // 创建对话控制总线混合阶段
					const FSoundControlBusMixStage VoiceChatControlBusMixStage = UAudioModulationStatics::CreateBusMixStage(World, VoiceChatControlBus, LyraSettingsLocal->GetVoiceChatVolume()); // 创建语音聊天控制总线混合阶段

					TArray<FSoundControlBusMixStage> ControlBusMixStageArray; // 创建控制总线混合阶段数组
					ControlBusMixStageArray.Add(OverallControlBusMixStage); // 添加总体混合阶段
					ControlBusMixStageArray.Add(MusicControlBusMixStage); // 添加音乐混合阶段
					ControlBusMixStageArray.Add(SoundFXControlBusMixStage); // 添加音效混合阶段
					ControlBusMixStageArray.Add(DialogueControlBusMixStage); // 添加对话混合阶段
					ControlBusMixStageArray.Add(VoiceChatControlBusMixStage); // 添加语音聊天混合阶段

					UAudioModulationStatics::UpdateMix(World, UserMix, ControlBusMixStageArray); // 更新混合
				}
			}

			ApplyDynamicRangeEffectsChains(LyraSettingsLocal->IsHDRAudioModeEnabled()); // 应用动态范围效果链
		}
	}
}

/**
 * 应用动态范围效果链
 * @param bHDRAudio 是否启用HDR音频
 */
void ULyraAudioMixEffectsSubsystem::ApplyDynamicRangeEffectsChains(bool bHDRAudio)
{
	TArray<FLyraAudioSubmixEffectsChain> AudioSubmixEffectsChainToApply; // 要应用的音频子混音效果链数组
	TArray<FLyraAudioSubmixEffectsChain> AudioSubmixEffectsChainToClear; // 要清除的音频子混音效果链数组

	// 如果选择HDR音频，则清除任何现有的LDR子混音效果链覆盖
	// 否则相反
	if (bHDRAudio)
	{
		AudioSubmixEffectsChainToApply.Append(HDRSubmixEffectChain); // 添加HDR子混音效果链到应用数组
		AudioSubmixEffectsChainToClear.Append(LDRSubmixEffectChain); // 添加LDR子混音效果链到清除数组
	}
	else
	{
		AudioSubmixEffectsChainToApply.Append(LDRSubmixEffectChain); // 添加LDR子混音效果链到应用数组
		AudioSubmixEffectsChainToClear.Append(HDRSubmixEffectChain); // 添加HDR子混音效果链到清除数组
	}

	// 我们想要收集实际需要清除的子混音，否则它们将被新设置覆盖
	TArray<USoundSubmix*> SubmixesLeftToClear; // 剩余要清除的子混音数组

	// 我们想要获取未被新效果链覆盖的子混音，以便我们可以单独清除它们
	for (const FLyraAudioSubmixEffectsChain& EffectChainToClear : AudioSubmixEffectsChainToClear)
	{
		bool bAddToList = true; // 是否添加到列表

		for (const FLyraAudioSubmixEffectsChain& SubmixEffectChain : AudioSubmixEffectsChainToApply)
		{
			if (SubmixEffectChain.Submix == EffectChainToClear.Submix) // 如果子混音相同
			{
				bAddToList = false; // 不添加到列表

				break; // 跳出循环
			}
		}

		if (bAddToList) // 如果需要添加到列表
		{
			SubmixesLeftToClear.Add(EffectChainToClear.Submix); // 添加子混音到剩余清除数组
		}
	}


	// 覆盖子混音
	for (const FLyraAudioSubmixEffectsChain& SubmixEffectChain : AudioSubmixEffectsChainToApply)
	{
		if (SubmixEffectChain.Submix) // 如果子混音存在
		{
			UAudioMixerBlueprintLibrary::SetSubmixEffectChainOverride(GetWorld(), SubmixEffectChain.Submix, SubmixEffectChain.SubmixEffectChain, 0.1f); // 设置子混音效果链覆盖

		}
	}

	// 清除剩余子混音
	for (USoundSubmix* Submix : SubmixesLeftToClear) // 遍历剩余要清除的子混音
	{
		UAudioMixerBlueprintLibrary::ClearSubmixEffectChainOverride(GetWorld(), Submix, 0.1f); // 清除子混音效果链覆盖
	}
}

/**
 * 加载屏幕状态改变时调用
 * @param bShowingLoadingScreen 是否显示加载屏幕
 */
void ULyraAudioMixEffectsSubsystem::OnLoadingScreenStatusChanged(bool bShowingLoadingScreen)
{
	ApplyOrRemoveLoadingScreenMix(bShowingLoadingScreen); // 应用或移除加载屏幕混合
}

/**
 * 应用或移除加载屏幕混合
 * @param bWantsLoadingScreenMix 是否想要加载屏幕混合
 */
void ULyraAudioMixEffectsSubsystem::ApplyOrRemoveLoadingScreenMix(bool bWantsLoadingScreenMix)
{
	UWorld* World = GetWorld(); // 获取世界

	// 如果应用状态与期望状态不同且加载屏幕混合存在且世界存在
	if (bAppliedLoadingScreenMix != bWantsLoadingScreenMix && LoadingScreenMix && World)
	{
		if (bWantsLoadingScreenMix) // 如果想要加载屏幕混合
		{
			// 应用混合
			UAudioModulationStatics::ActivateBusMix(World, LoadingScreenMix); // 激活总线混合
		}
		else
		{
			// 移除混合
			UAudioModulationStatics::DeactivateBusMix(World, LoadingScreenMix); // 停用总线混合
		}
		bAppliedLoadingScreenMix = bWantsLoadingScreenMix; // 更新应用状态
	}
}

/**
 * 判断是否支持世界类型
 * @param World 世界类型
 * @return 是否支持世界类型
 */
bool ULyraAudioMixEffectsSubsystem::DoesSupportWorldType(const EWorldType::Type World) const
{
	// 我们只需要在游戏世界（包括PIE）上使用此子系统
	return (World == EWorldType::Game || World == EWorldType::PIE); // 返回是否为游戏或PIE世界
}